﻿using System;
using System.Text;

namespace 面向对象_泛型1
{
    class Program
    {
        static void Main(string[] args)
        {
            var Ar = new Person<string, int>("包子", 66, "耀耀");
            Ar.Eat();
            Ar.Drink();

            //var obj = new object();
            //var sa = new sample<Base>((Base)obj);//可以在它们与 System.Object之间来回转换(类型转换)，或将它们显式转换为任何接口类型。

            // 测试获取任意接口 ，as 复习
            var bs = new Base();
            var sp = new sample<Base>(bs);
            IEatable et = sp.ReturnInterface();//不可以任意获取接口，只有被继承的才可以获取
            Console.WriteLine(et.GetType());
            IEatable2 et2 = sp.ReturnInterface2();//base没有继承IEatable2所以为空
            Console.WriteLine(et2);
            // 可以将它们与[null] 进行比较。 将未绑定的参数与 null进行比较时，如果类型参数为值类型，则该比较将始终返回 false。
            var a = new sample<int>(0);
            Console.WriteLine($"数值与null判断{a.Comparenull()}");//值类型永远返回false，无法判定是否为null
            var b = new sample<Base>(new Base());
            Console.WriteLine($"数值与null判断{b.Comparenull()}");
            b = new sample<Base>(null);
            Console.WriteLine($"对象与 null 判断 = {b.Comparenull()}"); //可以判断对象实例是否为null

            // int? : 可空类型，见 43 行，可以赋 null 值
            // string ?
            var c = new sample<int?>(555);//可以为空，也可以不为空
            Console.WriteLine($"数值与 null 判断 = {c.Comparenull()}");
            c = new sample<int?>(null);
            Console.WriteLine($"数值与 null 判断 = {c.Comparenull()}");


        }
    }
    // 多个泛型进行约束，使用多个 where 关键字，且无需使用“ ，”
    /// <summary>
    /// 人类
    /// </summary>
    /// <typeparam name="T">A</typeparam>
    /// <typeparam name="V">B</typeparam>
    public class Person<T, V>where T:class where V:struct
    {
        private T Argt;//使用泛型必须初始化
        private V Argv;
        private string Name;

        public Person(T argt,V argv,string name)
        {
            this.Argt = argt;
            this.Argv = argv;
            this.Name = name;
        }
        public void Eat()
        {
            Console.WriteLine($"{Name}再吃{Argt},等会喝{Argv.GetType()}");//GetType:获取类型 int32

            


            // 通过下面的示例说明，在 泛型 T where:class 时，避免使用 “==” “!=”,因为有可能与预期的结构不符。
            // 因为这些运算符将仅测试引用身份,而不测试值相等性.
            string a = "666";
            string b = "666";
            string c = new StringBuilder("666").ToString();
            Console.WriteLine(a==b);//true 测试值相等、
            Console.WriteLine(Compare<string>(a,b));//将参数传入测试地址是否相同，true地址相同

            Console.WriteLine(a==c);//true 测试值相等
            Console.WriteLine(Compare<string>(a, c));//测试地址是否相同，false地址不同
        }
       public  void Drink()
        {
            Console.WriteLine($"{Name} 在喝 {Argv}");
        }

        private bool Compare<u>(u lv, u rv)where u:class//将两个参数约束为引用类型
        {
            return lv == rv;//返回lv和rv比较的结果
        }
    }
    //sample :取样，示例，例子
    // 未做类型约束的，或未指定类型 称为未绑定的类型参数
    //没有约束的类型参数（如公共类 SampleClass<T>{}中的 T）称为未绑定的类型参数。
    //未绑定的类型参数具有以下规则：
    //1.  不能使用 !=和 == 运算符，因为无法保证具体类型参数能支持这些运算符。
    //2. 可以在它们与 System.Object之间来回转换(类型转换)，或将它们显式转换为任何接口类型。
    //因为没有指定是class 还是 struct ，所以用最大兼容性object
    // 3. 可以将它们与 [null] 进行比较。 将未绑定的参数与 null进行比较时，如果类型参数为值类型，则该比较将始终返回 false。

    public class sample<T>//未做类型约束，称为未绑定的类型参数
    {
        public T value;
        public sample(T value)
        {
            this.value = value;
        }
         //lv = left value 左边的值
         //rv = right value右边的值
        //public bool Compare(T lv,T rv)
        //{
            //return lv == rv;
            //return lv != rv;//不能使用 !=和 == 运算符，因为无法保证具体类型参数能支持这些运算符。
        //}

        public object Returnt()
        {
            return value;
        }
        public IEatable ReturnInterface()
        {
            return value as IEatable;//as运算符进行强转
        }

        public IEatable2 ReturnInterface2()
        {
            return value as IEatable2;
        }
        public bool Comparenull()
        {
            return value == null;
        }

    }
    public class Base:IEatable
    {

    }
    public interface IEatable { }
    public interface IEatable2 { }

}
